package com.devbobcorn.nekorization.client.model;

import com.devbobcorn.nekorization.client.event.ClientModEventSubscriber;
import com.devbobcorn.nekorization.entities.NekoEntity;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;

import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.model.geom.ModelLayers;
import net.minecraft.client.model.geom.ModelPart;
import net.minecraft.client.model.geom.PartPose;
import net.minecraft.client.model.geom.builders.CubeListBuilder;
import net.minecraft.client.model.geom.builders.LayerDefinition;
import net.minecraft.client.model.geom.builders.MeshDefinition;
import net.minecraft.client.model.geom.builders.PartDefinition;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.util.Mth;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;

@OnlyIn(Dist.CLIENT)
public class NekoModel<T extends NekoEntity> extends PlayerModel<T> {
	private static final int CROUCH_STATE = 0;
	private static final int WALK_STATE = 1;
	private static final int SPRINT_STATE = 2;
	private static final int SITTING_STATE = 3;

	public final ModelPart tail1;
	public final ModelPart tail2;
	protected int state = 1;

	public NekoModel(EntityRendererProvider.Context ctx, boolean slim) {
		super(ctx.bakeLayer(slim ? ModelLayers.PLAYER_SLIM : ModelLayers.PLAYER), slim);
		ModelPart tailModel = ctx.bakeLayer(ClientModEventSubscriber.NEKO_TAIL);
		this.tail1 = tailModel.getChild("tail1");
		this.tail2 = tailModel.getChild("tail2");
	}

	public static LayerDefinition createTailLayer() {
		MeshDefinition meshdefinition = new MeshDefinition();
		PartDefinition partdefinition = meshdefinition.getRoot();
		partdefinition.addOrReplaceChild("tail1",
				CubeListBuilder.create().texOffs(60, 16).addBox(-0.5F, 0.0F, 0.0F, 1.0F, 8.0F, 1.0F),
				PartPose.offsetAndRotation(0.0F, 15.0F, 8.0F, 0.9F, 0.0F, 0.0F));
		partdefinition.addOrReplaceChild("tail2",
				CubeListBuilder.create().texOffs(56, 16).addBox(-0.5F, 0.0F, 0.0F, 1.0F, 8.0F, 1.0F),
				PartPose.offset(0.0F, 20.0F, 14.0F));
		return LayerDefinition.create(meshdefinition, 64, 64);
	}

	@Override
	public void prepareMobModel(T entity, float a, float b, float c) {
		super.prepareMobModel(entity, a, b, c);
		this.tail1.y = 10.0F;
		this.tail1.z = 0.0F;
		this.tail2.y = 15.0F;
		this.tail2.z = 6.0F;
		this.tail1.xRot = 0.9F;
		if (entity.isCrouching()) {
			++this.tail1.y;
			this.tail2.y += -4.0F;
			this.tail2.z += 2.0F;
			this.tail1.xRot = ((float) Math.PI / 2F);
			this.tail2.xRot = ((float) Math.PI / 2F);
			this.state = CROUCH_STATE;
		} else if (entity.isSprinting()) {
			this.tail2.y = this.tail1.y;
			this.tail2.z += 2.0F;
			this.tail1.xRot = ((float) Math.PI / 2F);
			this.tail2.xRot = ((float) Math.PI / 2F);
			this.state = SPRINT_STATE;
		} else {
			this.state = WALK_STATE;
		}
	}

	@Override
	public void setupAnim(T entity, float a, float b, float c, float d, float e) {
		if (entity.isInSittingPose()) {
			// Use riding pose...
			this.riding = true;
		}
		super.setupAnim(entity, a, b, c, d, e);
		// Set tail... (Copied from OcelotModel)
		if (this.state != SITTING_STATE) {
			if (this.state == SPRINT_STATE) {
				this.tail2.xRot = 1.7278761F + ((float) Math.PI / 10F) * Mth.cos(a) * b;
			} else {
				if (this.state == WALK_STATE) {
					this.tail2.xRot = 1.7278761F + ((float) Math.PI / 4F) * Mth.cos(a) * b;
				} else {
					this.tail2.xRot = 1.7278761F + 0.47123894F * Mth.cos(a) * b;
				}
			}
		}
	}

	@Override
	public Iterable<ModelPart> bodyParts() { // Add tail parts...
		return Iterables.concat(super.bodyParts(), ImmutableList.of(this.tail1, this.tail2));
	}

	@Override
	public void setAllVisible(boolean visibility) { // Add tail parts...
		super.setAllVisible(visibility);
		this.tail1.visible = visibility;
		this.tail2.visible = visibility;
	}
}